#include <cstdio>
#include <algorithm>

using namespace std;

struct Edge
{
    int x, y, cost;
    Edge( ) { }
    Edge( int _x, int _y, int _cost )
        : x( _x ), y( _y ), cost( _cost ) { }
};

bool operator < ( const Edge &a, const Edge &b )
{
    return a.cost < b.cost;
}

Edge edge[ 11000 ];
int e, sum, n, s[ 110 ];

void unionset( int root1, int root2 )
{
    s[ root1 ] = root2;
}

int find( int x )
{
    if ( s[ x ] < 0 )
        return x;
    else
        return s[ x ] = find( s[ x ] );
}

void init( )
{
    int i, j, a, b, c, v1, v2, q;
    e = 0;
    for ( i = 1; i <= n; i++ )
        for ( j = 1; j <= n; j++ )
        {
            scanf("%d", &c);
            if ( c >= 1 && c <= 1000 )
                edge[ e++ ] = Edge( i, j, c );
        }
    for ( i = 1; i <= n; i++ )
        s[ i ] = -1;
    scanf("%d", &q);
    for ( i = 0; i < q; i++ )
    {
        scanf("%d%d", &a, &b);
        v1 = find( a );
        v2 = find( b );
        if ( v1 != v2 )
        {
            n--;
            unionset( v1, v2 );
        }
    }
}

void Kruscal( )
{
    int i, j, v1, v2;
    sum = i = j = 0;
    while ( j < n && i < e )
    {
        v1 = find( edge[ i ].x );
        v2 = find( edge[ i ].y );
        if ( v1 != v2 )
        {
            sum += edge[ i ].cost;
            unionset( v1, v2 );
            j++;
        }
        i++;
    }
}

void print( )
{
    int i, t1, t2;
    t1 = find( 1 );
    for ( i = 2; i <= n; i++ )
        if ( find( i ) != t1 )
            break;
    if ( i > n )
        printf("%d\n", sum);
    else
        printf("?\n");
}

int main( )
{
    while ( scanf("%d", &n) != EOF )
    {
        init( );
        sort( edge, edge + e );
        Kruscal( );
        print( );
    }
    return 0;
}
